package com.cskaoyan.thread01;

/*

       很好理解，解决多线程数据安全问题，是通过加锁，构造一个线程对共享变量的原子操作。
      但其实，加锁是在完成线程同步
      涉及两个概念：
      1. 同步：  你走我不走，我走你不走，所有加锁失败的线程，步调变的一致了，都需要等待锁对象被释放

      2. 异步： 你走你的，我走我的，多线程天生异步，不同的线程，相互独立互不影响，
               各自按照，按照各自的执行步调，执行各自代码

      所以，最终，其实我们线程同步，来解决多线程的数据安全问题的
      线程同步的优缺点：
      优点：解决了多线程线程安全问题。
      缺点：相比于异步，因为等待锁资源而引发的阻塞，降低了程序运行效率。


      同步方法:  相当于将方法的方法体变成了一个大的 同步代码块
      同步方法的锁对象是谁呢？
      a. 普通成员方法， 其锁对象是隐式的，就是该方法运行时的当前对象 this
      b. 静态方法，静态方法属于类，静态方法的锁对象就是静态方法所属类对应的Class对象




 */
public class Demo1 {

    public static void main(String[] args) {
        // 创建售票任务对象
        SalesTask salesTask = new SalesTask();

        Thread firstWindow = new Thread(salesTask, "first");
        Thread secondWindow = new Thread(salesTask, "second");
        Thread thirdWindow = new Thread(salesTask, "third");

        // 启动三个线程，模拟三个窗口售票
        firstWindow.start();
        secondWindow.start();
        thirdWindow.start();
    }
}

class SalesTask implements Runnable {

    //待售卖的100张票
    // 普通成员变量
    int tickets = 100;

    @Override
    public void run() {
        //  售卖100张票
        while (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // 实现线程同步
            salesTicket();
        }
    }

    /*
         将整个方法体变成同步代码块，于是该方法
         就变成了同步方法，它的锁对象即方法当前对象this
     */
    private synchronized void salesTicket() {

        // 判断是否有票  double check
        if (tickets > 0) {
            System.out.println(Thread.currentThread().getName() + "售出了第" + tickets-- + "张票");
        }

    }

    /*
          静态方法也可以被定义为同步方法
     */
    public synchronized static void staticMethod() {

    }
}
